package com.sunxd.integration.platform.classloader;

import com.sunxd.integration.platform.constants.ClassLoaderConstant;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;

import static com.sunxd.integration.platform.constants.ClassLoaderConstant.BASE_PACKAGE_NAME;
import static com.sunxd.integration.platform.constants.ClassLoaderConstant.CLASS_PATH;
import static com.sunxd.integration.platform.constants.ClassLoaderConstant.RT;

/**
 * @author sun.xd
 * @description: description
 * @date 2022/9/8 11:10
 */
public class MyClassLoader extends ClassLoader {

    //生成类的源文件，写成字符串的形式
    public String src = "package " + BASE_PACKAGE_NAME + ";" + RT;

    //类名 类的全限定包名 不带后缀  例如com.test.Notice
    private String className;

    private String classPackageName;

    private String javaPackageName;

    private MyClassLoader() {
    }

    public MyClassLoader(String controllerName,String src) {
        className = BASE_PACKAGE_NAME + "." + controllerName;
        System.out.println(CLASS_PATH);
        String packageName = CLASS_PATH + className.replace(".", File.separator);//类名转换路径
        classPackageName = packageName + ClassLoaderConstant._CLASS;
        javaPackageName = packageName + ClassLoaderConstant._JAVA;
        this.src =  this.src + src;

    }

    /**
     * 写文件
     */
    private void writerFile() throws IOException {
        File file = new File(javaPackageName);
        FileWriter fw = new FileWriter(file);
        fw.write(src);
        fw.flush();
        fw.close();
    }

    /**
     * 编译java类
     * 使用rt.jar中的javax.tools包提供的编译器
     */
    private void compiler() {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null);
        Iterable<? extends JavaFileObject> units = sjfm.getJavaFileObjects(javaPackageName);
        JavaCompiler.CompilationTask ct = compiler.getTask(null, sjfm, null, null, null, units);
        ct.call();
    }

    /**
     * 复写父类的类加载方法
     *
     * @param name 类的全限定包名 不带后缀  例如com.test.Notice  而不要写成com.test.Notice.java
     * @return Class
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        //加载类的字节码
        byte[] classBytes;
        try {
            classBytes = Files.readAllBytes(Paths.get(classPackageName));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Class<?> clazz;
        //将字节码交给JVM
        clazz = defineClass(name, classBytes, 0, classBytes.length);
        if (clazz == null) {
            throw new ClassNotFoundException(name);
        }
        return clazz;
    }

    /**
     * 动态编译一个java源文件并加载编译生成的class
     */
    public Class<?> dynamicLoadClass() throws ClassNotFoundException, IOException {
        //1、先将字符串源码写入java文件
        writerFile();
        //2、将java文件编译成class文件
        compiler();
        //3、把编译好的的交给JVM
        Class<?> clazz = findClass(className);
        return clazz;
    }

}
